import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';

typedef ValueGetter<T> = T Function();

class DGGSignatureInterceptor extends Interceptor {
  final ValueGetter<String>? sysCode;
  final ValueGetter<String>? sysKey;

  DGGSignatureInterceptor({this.sysCode, this.sysKey})
      : assert(sysCode != null && sysKey != null);

  @override
  void onRequest(RequestOptions options,RequestInterceptorHandler handler,) async {
    Map<String, dynamic> header;
    if (options.method == 'GET') {
      //只针对query 签名
      header = _getSignHeaders(query: options.uri.queryParameters);
    } else {
      //只针对body签名
      var data = options.data;
      if (data is Map) {
        header = _getSignHeaders(body: data);
      } else if (data is String) {
        header = _getSignHeaders(body: json.decode(data));
      } else {
        Map<dynamic, dynamic> body = {};
        header = _getSignHeaders(body: body);
      }
    }

    if (options.headers != null && options.headers.length > 0) {
      var map = Map<String, dynamic>();
      map.addAll(options.headers);
      if (header != null) map.addAll(header);
      header = map;
    }
    options.headers = header;
    super.onRequest(options, handler);
  }

  //接收String 和 Map 两种类型
  Map<String, dynamic> _getSignHeaders({Map? body, Map? query}) {
    var nonce = _getNonce(10);
    var timestamp = new DateTime.now().millisecondsSinceEpoch;
    String? params;
    if (body != null && body.length > 0) {
      params = json.encode(body);
    } else if (query != null && query.length > 0) {
      //Get 需要排序
      params = _mapToString(query, isSort: true);
    }
    var sign = _getSign(timestamp, nonce, params!);
    return {
      'nonce': nonce,
      'time': timestamp,
      'sign': sign,
      'sysCode': sysCode!(),
      'X-Req-Client': Platform.isAndroid ? 'ANDROID' : 'IOS',
      'X-Req-YT': 'BUS_YT_CY',
    };
  }

  String _getSign(int time, String nonce, String requestParams) {
    var sinParams = {
      'nonce': nonce,
      'time': time,
      'data': requestParams,
    };
    String sinStr = _mapToString(sinParams, isSort: true);
    return _createSign(sinStr);
  }

  String _createSign(String signParamStr) {
    String appendStr = '$signParamStr&sysCode=${sysCode!()}&secret=${sysKey!()}';
    var content = new Utf8Encoder().convert(appendStr);
    var digest = md5.convert(content);
    return digest.toString().toUpperCase();
  }

  //排序更据key，返回 xxxx=xxxx&yyyy=yyyy  没有大括号
  String _mapToString(Map data, {bool isSort = true}) {
    if (data == null) return '';
    var keys = data.keys.toList();
    if (isSort) {
      keys.sort();
    }
    StringBuffer result = StringBuffer();
    keys.forEach((key) {
      var value = data[key];
      if (value != null) {
        if (result.length > 0) {
          result.write('&');
        }
        result.write('$key=$value');
      }
    });
    return result.toString();
  }

  String _getNonce(int length) {
    var timestamp = DateTime.now().millisecondsSinceEpoch + 1;
    String scopeF = '123456789'; //首位
    String scopeC = '0123456789'; //中间
    String result = '';
    var random = Random();
    for (int i = 0; i < length; i++) {
      if (i == 1) {
        result = scopeF[random.nextInt(scopeF.length)];
      } else {
        result = result + scopeC[random.nextInt(scopeC.length)];
      }
    }
    String nonce = '$timestamp$result';
    return nonce;
  }
}
